// Copyright (c) 2014-2023 All rights reserved
// -----------------------------------------------------------------------------
// Author       : HiDark 1173296519@qq.com
// File         : mat_scan.v
// Create       : 2023-12-25 16:46:32
// Description  : ZigZag matrix scan ,serial in/out
// Editor       : tab size (4)
// -----------------------------------------------------------------------------
module mat_scan
(
    // Inputs
    input                   clk,
    input                   rst_n,
    input                   vld_in,
    input          [9:0]    din,
    // outputs    
    output  reg             vld_out,
    output  wire    [9:0]    dout
);
localparam IDLE = 2'b00,WRITE = 2'b01 ,READ = 2'b10,DONE = 2'b11;
wire [5:0] sram_addr;
reg [1:0] state,next_state;
reg csn, wen, vld_out_next;
reg [5:0] addr,raddr;

assign sram_addr = (state == WRITE)?addr:raddr;
//-----------------------------------------------------------------
// FSM: State switch
//-----------------------------------------------------------------
always @(posedge clk or negedge rst_n) begin 
    if(~rst_n) 
        state <= IDLE;
    else 
        state <= next_state;
end

always @(*) begin 
    case (state)
        IDLE: if(vld_in)  next_state = WRITE;
                else next_state = IDLE;
        WRITE : if(addr == 6'd63)  next_state = READ;
                else next_state = WRITE;        
        READ  : if(addr == 6'd63) next_state = IDLE;
                else next_state = READ;             
        default : next_state = state;
    endcase       
end
always @(posedge clk or negedge rst_n) begin 
    if(~rst_n) 
        addr <= 0;
    else if (state == READ || vld_in)
        addr <= addr +1;
end
always @(posedge clk or negedge rst_n) begin 
    if(~rst_n) 
        vld_out <= 0;
    else 
        vld_out <= vld_out_next;
end
always @(*) begin 
    case (state)
        IDLE: if(vld_in)  begin
                wen  = 1'b0;
                csn  = 1'b0;
                vld_out_next = 1'b0; 
        end
             else begin
                wen  = 1'b1;
                csn  = 1'b1; 
                vld_out_next = 1'b0; 
        end
        WRITE: if(vld_in)  begin
                wen  = 1'b0;
                csn  = 1'b0;
                vld_out_next = 1'b0;  
        end 
             else begin
                wen  = 1'b1;
                csn  = 1'b0; 
                vld_out_next = 1'b0; 
        end       
        READ : begin
                wen  = 1'b1;
                csn  = 1'b0;
                vld_out_next = 1'b1;  
        end 
        default : begin
                wen  = 1'b1;
                csn  = 1'b1;
                vld_out_next = 1'b0; 
        end 
    endcase       
end

always @(*) begin
    case (addr)
    6'd0 : raddr = 6'd0;
    6'd1 : raddr = 6'd1;
    6'd2 : raddr = 6'd8;
    6'd3 : raddr = 6'd16;
    6'd4 : raddr = 6'd9;
    6'd5 : raddr = 6'd2;
    6'd6 : raddr = 6'd3;
    6'd7 : raddr = 6'd10;
    6'd8 : raddr = 6'd17;
    6'd9 : raddr = 6'd24;
    6'd10: raddr = 6'd32;
    6'd11: raddr = 6'd25;
    6'd12: raddr = 6'd18;
    6'd13: raddr = 6'd11;
    6'd14: raddr = 6'd4;
    6'd15: raddr = 6'd5;
    6'd16: raddr = 6'd12;
    6'd17: raddr = 6'd19;
    6'd18: raddr = 6'd26;
    6'd19: raddr = 6'd33;
    6'd20: raddr = 6'd40;
    6'd21: raddr = 6'd48;
    6'd22: raddr = 6'd41;
    6'd23: raddr = 6'd34;
    6'd24: raddr = 6'd27;
    6'd25: raddr = 6'd20;
    6'd26: raddr = 6'd13;
    6'd27: raddr = 6'd6;
    6'd28: raddr = 6'd7;
    6'd29: raddr = 6'd14;
    6'd30: raddr = 6'd21;
    6'd31: raddr = 6'd28;
    6'd32: raddr = 6'd35;
    6'd33: raddr = 6'd42;
    6'd34: raddr = 6'd49;
    6'd35: raddr = 6'd56;
    6'd36: raddr = 6'd57;
    6'd37: raddr = 6'd50;
    6'd38: raddr = 6'd43;
    6'd39: raddr = 6'd36;
    6'd40: raddr = 6'd29;
    6'd41: raddr = 6'd22;
    6'd42: raddr = 6'd15;
    6'd43: raddr = 6'd23;
    6'd44: raddr = 6'd30;
    6'd45: raddr = 6'd37;
    6'd46: raddr = 6'd44;
    6'd47: raddr = 6'd51;
    6'd48: raddr = 6'd58;
    6'd49: raddr = 6'd59;
    6'd50: raddr = 6'd52;
    6'd51: raddr = 6'd45;
    6'd52: raddr = 6'd38;
    6'd53: raddr = 6'd31;
    6'd54: raddr = 6'd39;
    6'd55: raddr = 6'd46;
    6'd56: raddr = 6'd53;
    6'd57: raddr = 6'd60;
    6'd58: raddr = 6'd61;
    6'd59: raddr = 6'd54;
    6'd60: raddr = 6'd47;
    6'd61: raddr = 6'd55;
    6'd62: raddr = 6'd62;
    default: raddr = 6'd63; 
    endcase
end
//-----------------------------------------------------------------
// Instant SRAM
//-----------------------------------------------------------------
SRAM_SP #(
        .ADDR_WIDTH(6),
        .DATA_WIDTH(10),
        .DATA_DEPTH(64)
    ) inst_SRAM_SP (
        .clk  (clk),
        .wen  (wen),
        .csn  (csn),
        .addr (sram_addr),
        .din  (din),
        .dout (dout)
    );

endmodule